Skip to content

Conversation

@abe238
Copy link
Contributor

@abe238 abe238 commented Dec 31, 2025

Summary

  • Updated parsePythonCommand to check for path separators BEFORE existsSync to properly handle paths that may not exist yet
  • Added macOS Application Support and Windows AppData patterns to ALLOWED_PATH_PATTERNS for Electron userData venv paths
  • Changed python-env-manager to use execFileSync instead of execSync to avoid shell interpretation issues with spaces

Problem

When using the packaged app on macOS, the venv Python path contains spaces:
/Users/user/Library/Application Support/App/python-venv/bin/python

This was causing spawn ENOENT errors during merge operations because the path was being incorrectly split at the space character.

Root Cause

The parsePythonCommand function was checking existsSync() before checking if the path looked like a file path. If the file didn't exist (e.g., during initial setup), and the path wasn't recognized as a path, it would fall through to splitting on spaces.

Fix

  1. Reorder checks: Check for path separators (/ or \) FIRST, before checking file existence
  2. Add userData patterns: Added regex patterns for:
    • macOS: /Users/<user>/Library/Application Support/<app>/python-venv/bin/python
    • Windows: C:\Users\<user>\AppData\Roaming\<app>\python-venv\Scripts\python.exe
  3. Use execFileSync: Changed python-env-manager.ts to use execFileSync with shell: false to avoid shell interpretation issues

Test Plan

  • Test merge operation on macOS with packaged app
  • Test merge operation on Windows with packaged app
  • Verify venv creation still works with paths containing spaces

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Safer Python detection/resolution: handles paths with spaces, avoids shell interpretation, adds validation and runtime verification for candidate executables.
  • New Features

    • Multi-shell support for terminal login and third-party invocation (PowerShell, cmd, bash/zsh, fish, sh) with shell-aware command generation and env handling.
    • Terminal processes include an optional shell type for consistent behavior.
  • Tests

    • Comprehensive tests for shell-escaping, shell detection, command builders, and Python-path validation.
  • Documentation

    • Expanded comments clarifying path-handling semantics and validation order.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Reworks Python command parsing and validation to safely handle path-like strings and spaces, switches execSync -> execFileSync with parsed args, expands allowed Python path patterns and runtime verification, and adds multi-shell detection plus shell-aware escaping and command builders for terminal login and Claude flows.

Changes

Cohort / File(s) Summary
Python detection & validation
apps/frontend/src/main/python-detector.ts
Adds parsePythonCommand, safer exec via execFileSync (no shell), expanded ALLOWED_PATH_PATTERNS and SAFE_PYTHON_COMMANDS, path-like detection (preserve paths with spaces), dangerous-char checks, --version verification, and helper validators.
Python env resolution caller
apps/frontend/src/main/python-env-manager.ts
findSystemPython now uses parsePythonCommand + execFileSync (cmd + args) to resolve Python without shell interpretation, preserving timeout behavior.
Shell escaping utilities & tests
apps/frontend/src/shared/utils/shell-escape.ts, apps/frontend/src/shared/utils/shell-escape.test.ts
Adds ShellType and detectShellType; introduces escapeShellArgWindows, escapeShellArgPowerShell, newline sanitization in escapeShellArg, isPathSafe, and buildCdCommandForShell; extensive unit tests added.
Terminal login & Claude integration
apps/frontend/src/main/ipc-handlers/terminal-handlers.ts, apps/frontend/src/main/terminal/claude-integration-handler.ts, apps/frontend/src/main/terminal/types.ts
Detects shell type and builds shell-specific login/Claude commands (PowerShell, cmd, fish, bash/zsh/sh); adds logging; invokeClaude accepts optional shellType?; TerminalProcess gains optional shellType?: ShellType.
Terminal tests & detector tests
apps/frontend/src/main/__tests__/python-detector.test.ts, apps/frontend/src/shared/utils/shell-escape.test.ts
Adds/expands tests for parsePythonCommand, validatePythonPath, shell detection, and per-shell escaping/command builders covering many edge cases and injection patterns.

Sequence Diagram(s)

sequenceDiagram
  participant UI as Renderer (UI)
  participant Main as Main (IPC handlers)
  participant Detector as Python Detector
  participant ShellUtil as Shell Utils
  participant ShellProc as Terminal Process

  rect rgba(120,160,255,0.06)
    Note over UI,ShellProc: Shell-aware terminal login / Claude invocation with Python validation
  end

  UI->>Main: request startTerminal/login (env, token, optional shellPath)
  Main->>ShellUtil: detectShellType(shellPath)
  ShellUtil-->>Main: ShellType
  Main->>Detector: parsePythonCommand(commandStr)
  Detector-->>Main: {cmd, args} and validation result
  Main->>ShellUtil: escape token/args for ShellType
  ShellUtil-->>Main: escaped command fragments
  Main->>ShellProc: spawn shell with assembled shell-specific command
  ShellProc-->>Main: started / stdout / exit
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

area/frontend, os/macos, size/S

Suggested reviewers

  • MikeeBuilds
  • AndyMik90
  • AlexMadera

Poem

🐰 I hopped through quotes and escaped each gap,
I kept your tokens snug inside a map.
Paths with spaces I proudly defend,
I learn each shell and stitch each end.
Hooray — the rabbit’s careful clap! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: handling Python paths with spaces, which is the core issue addressed across multiple files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a79a02d and 484aef0.

📒 Files selected for processing (2)
  • apps/frontend/src/main/python-detector.ts
  • apps/frontend/src/shared/utils/shell-escape.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/main/python-detector.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (11)
apps/frontend/src/shared/utils/shell-escape.ts (5)

8-68: LGTM! Shell type detection is well-structured.

The detectShellType function correctly identifies various shell types with reasonable defaults. The order of checks is appropriate (more specific patterns before generic ones), and defaulting to bash for unknown shells is a sensible POSIX-compatible fallback.


86-93: Good security fix: newline/CR sanitization prevents command injection.

Stripping \r\n before escaping single quotes closes a command injection vector where an attacker could break out of single-quoted strings using newlines. This is a solid defense-in-depth approach.


147-170: LGTM! Shell-specific cd command generation is well-implemented.

The function correctly uses:

  • Set-Location with semicolon separator for PowerShell
  • cd /d with & separator for cmd.exe (supporting drive changes)
  • Standard cd with && for POSIX shells

Each shell type uses its appropriate escaping function.


182-200: Good security hardening with newline removal.

The addition of \r and \n removal (lines 196-197) closes a command injection vector in cmd.exe. The order of escape operations is correct—carets are escaped first since ^ is the escape character.


219-226: LGTM! PowerShell escaping is correct.

PowerShell single-quoted strings only require doubling single quotes ('''), and newline sanitization is properly applied before escaping.

apps/frontend/src/main/python-detector.ts (6)

1-1: Good security improvement: switching to execFileSync.

Using execFileSync with shell: false prevents shell injection attacks when executing Python commands, especially important for paths containing spaces or special characters.


119-135: LGTM! Safe Python version extraction.

Using execFileSync with shell: false and parsePythonCommand correctly handles paths with spaces without shell interpretation issues.


230-268: LGTM! Correct reordering fixes the path-with-spaces issue.

The key fix: checking for path separators (/ or \) before existsSync ensures that paths like /Users/user/Library/Application Support/App/python-venv/bin/python are treated as single paths rather than split on spaces, even when the venv doesn't exist yet during initial setup.

The logic flow is now:

  1. Has path separators and doesn't start with - → treat as path (no split)
  2. File exists without separators → treat as executable in current directory
  3. Otherwise → split on spaces for commands like py -3

This correctly handles the root cause described in the PR.


377-392: LGTM! Safe Python verification.

Using execFileSync with shell: false and verifying the output matches Python X.Y is a solid defense-in-depth measure to ensure the executable is actually Python.


406-495: Comprehensive validation with good layered security.

The validation flow is well-structured:

  1. Shell metacharacter rejection
  2. Safe command allowlist check
  3. Path traversal detection
  4. Allowlist pattern matching
  5. Existence and executability checks
  6. Runtime Python verification

This defense-in-depth approach significantly reduces command injection risk.


296-307: The regex patterns work correctly; the concern about unescaped spaces is based on a misunderstanding of regex syntax.

Spaces inside character classes [ ] do not require escaping and are literal characters in regex. The test results confirm all patterns match their intended paths:

  • Virtual environment patterns correctly match /home/user/my-project/.venv/bin/python paths
  • macOS Application Support pattern correctly matches /Users/*/Library/Application Support/*/venv/bin/python paths
  • Character classes with spaces function as intended

The patterns are internal path validation logic, not user-facing text, so no changes are needed.

Likely an incorrect or invalid review comment.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 31, 2025

All contributors have signed the CLA. Thank you!
Posted by the CLA Assistant Lite bot.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @abe238, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves a critical issue where Python paths containing spaces, particularly those found in Electron application data directories on macOS and Windows, were causing spawn ENOENT errors. The changes ensure that such paths are correctly parsed and executed by reordering path validation logic, expanding the set of recognized path patterns, and adopting execFileSync for command execution to bypass shell interpretation problems. This significantly enhances the stability and compatibility of Python environment management within the application.

Highlights

  • Improved Python Path Parsing: The parsePythonCommand function has been updated to prioritize checking for path separators before verifying file existence. This ensures that Python paths containing spaces (e.g., in macOS Application Support directories) are correctly identified as single paths and not incorrectly split into multiple arguments, even if the file doesn't exist yet during initial setup.
  • Expanded Allowed Path Patterns: New regex patterns have been added to ALLOWED_PATH_PATTERNS to explicitly recognize common Electron userData virtual environment paths on both macOS (e.g., /Library/Application Support/) and Windows (e.g., AppData/Roaming/). These paths frequently contain spaces and are now properly validated.
  • Switched to execFileSync for Robust Execution: The python-env-manager.ts file now uses execFileSync instead of execSync when resolving the actual Python executable path. By setting shell: false, this change prevents shell interpretation issues that could arise from spaces within Python paths, ensuring more reliable command execution.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively resolves the issue of handling Python paths with spaces, which was causing errors on platforms like macOS. The core logic change in parsePythonCommand to prioritize path structure over file existence is a solid fix. Additionally, switching to execFileSync from execSync is a great improvement for both security and robustness, preventing shell interpretation issues. The new regex patterns for Electron's userData paths on both macOS and Windows are also a necessary addition. I've included a couple of suggestions to consolidate similar regular expressions for improved maintainability. Overall, this is a well-executed fix.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 203a970 and 54bb603.

📒 Files selected for processing (2)
  • apps/frontend/src/main/python-detector.ts
  • apps/frontend/src/main/python-env-manager.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/python-env-manager.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/python-env-manager.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/python-env-manager.ts
  • apps/frontend/src/main/python-detector.ts
🪛 GitHub Actions: CI
apps/frontend/src/main/python-env-manager.ts

[error] 205-205: TypeScript error: Cannot find name 'parsePythonCommand'.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (4)
apps/frontend/src/main/python-detector.ts (3)

211-213: Excellent documentation enhancement.

The added emphasis on handling paths with spaces is clear and directly addresses the root cause described in the PR. This will help prevent future regressions.


237-255: Core fix correctly implements path-with-spaces handling.

The reordering of checks is the key improvement:

  1. Path separator detection now happens before existence checks
  2. Paths with separators are returned as-is without splitting on spaces
  3. This correctly handles venv paths that don't exist yet during setup

The logic is sound and directly addresses the root cause of the ENOENT errors.


306-309: Pattern coverage is correct—no changes needed.

The added patterns accurately match Electron userData paths:

  • macOS: /Users/<user>/Library/Application Support/<app>/ is the standard userData location; non-standard home directories are not a practical concern.
  • Windows: AppData\Roaming\<app>\ is the correct userData location; AppData\Local is used only for system Python installations (already handled by line 318).
  • App name matching: [^/]+ and [^\\]+ correctly capture all app names while preventing directory traversal.

The generic patterns at lines 313–315 provide fallback coverage for Linux and other venv naming variations.

apps/frontend/src/main/python-env-manager.ts (1)

204-210: Correct fix for shell interpretation issues with spaces.

The change from execSync to execFileSync with shell: false is the right approach:

  • Prevents the shell from splitting paths at spaces
  • Uses parsePythonCommand to correctly parse the command
  • Maintains the same 5-second timeout for safety

This change works correctly once the missing import is added (see previous comment).

Note: This comment assumes the missing parsePythonCommand import will be added as suggested in the previous review comment.

@AlexMadera AlexMadera self-assigned this Dec 31, 2025
- Updated parsePythonCommand to check for path separators BEFORE
  existsSync to properly handle paths that may not exist yet
- Added macOS Application Support and Windows AppData patterns to
  ALLOWED_PATH_PATTERNS for Electron userData venv paths
- Changed python-env-manager to use execFileSync instead of execSync
  to avoid shell interpretation issues with spaces

Fixes spawn ENOENT errors when venv Python path contains spaces,
e.g., /Users/user/Library/Application Support/App/python-venv/bin/python

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Abe Diaz (@abe238) <[email protected]>
@abe238 abe238 force-pushed the fix/python-path-spaces branch from 54bb603 to 890704c Compare December 31, 2025 07:14
Copy link
Collaborator

@AlexMadera AlexMadera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

Merge Verdict: ✅ READY TO MERGE

No blocking issues found

Risk Assessment

Factor Level Notes
Complexity Low Based on lines changed
Security Impact Low Based on security findings
Scope Coherence Good Based on structural review

Findings Summary

  • Medium: 1 issue(s)
  • Low: 3 issue(s)

Generated by Auto Claude PR Review

Findings (4 selected of 4 total)

🟡 [MEDIUM] getPythonVersion still uses execSync with string interpolation

📁 apps/frontend/src/main/python-detector.ts:130

The getPythonVersion function at line 130 still uses execSync(${pythonCmd} --version) which could fail for paths containing spaces. This is inconsistent with the PR's goal of fixing space handling. While this function is primarily called with simple command names, the pattern should be updated for consistency with the execFileSync approach used elsewhere.

Suggested fix:

Update getPythonVersion to use parsePythonCommand() and execFileSync similar to verifyIsPython(): `const [cmd, args] = parsePythonCommand(pythonCmd); const version = execFileSync(cmd, [...args, '--version'], { stdio: 'pipe', timeout: 5000, windowsHide: true, shell: false }).toString().trim();`

🔵 [LOW] Edge case regression for files with spaces in name

📁 apps/frontend/src/main/python-detector.ts:234

The new logic order (checking path separators before existsSync) introduces a theoretical regression: if a user has an actual file literally named 'py -3' in the current directory, it would now be incorrectly split into ['py', ['-3']] instead of being recognized as a single file. This is an extremely unlikely scenario in practice.

Suggested fix:

Consider adding a comment documenting this behavioral change, or add a final existsSync check for non-path-like strings before splitting. Given the low probability of this edge case, this is acceptable for now.

🔵 [LOW] Regex patterns use permissive character class for app names

📁 apps/frontend/src/main/python-detector.ts:305

The new regex patterns use [^/]+ and [^\\]+ which allow any characters except path separators in the username and app name positions. While this works correctly and the existing path.normalize() and '..' check provide protection, using a more restrictive character class like [a-zA-Z0-9_\-. ]+ would reduce attack surface.

Suggested fix:

Consider tightening the regex to `/^\/Users\/[a-zA-Z0-9_\-. ]+\/Library\/Application Support\/[a-zA-Z0-9_\-. ]+\/python-venv\/bin\/python\d*(\.\d+)?$/` for defense in depth. The current pattern is acceptable given the existing validation layer.

🔵 [LOW] No unit tests for parsePythonCommand with space-containing paths

📁 apps/frontend/src/main/python-detector.ts:215

The PR adds critical logic for handling paths with spaces, but there are no unit tests specifically testing scenarios like '/Users/user/Library/Application Support/App/python-venv/bin/python'. The existing subprocess-spawn.test.ts tests the spawning but not the path parsing edge cases.

Suggested fix:

Add unit tests for parsePythonCommand covering: 1) paths with spaces that exist, 2) paths with spaces that don't exist yet, 3) simple commands like 'py -3', 4) Windows paths with spaces. This ensures the fix doesn't regress.

This review was generated by Auto Claude.

@abe238
Copy link
Contributor Author

abe238 commented Dec 31, 2025

I have read the CLA Document and I hereby sign the CLA

- Add missing parsePythonCommand import (CodeRabbit critical)
- Consolidate macOS Application Support regex patterns (Gemini)
- Consolidate Windows AppData Roaming regex patterns (Gemini)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@AndyMik90 AndyMik90 self-assigned this Dec 31, 2025
AlexMadera
AlexMadera previously approved these changes Dec 31, 2025
Copy link
Collaborator

@AlexMadera AlexMadera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

Merge Verdict: ✅ READY TO MERGE

No blocking issues found

Risk Assessment

Factor Level Notes
Complexity Low Based on lines changed
Security Impact Low Based on security findings
Scope Coherence Good Based on structural review

Findings Summary

  • Medium: 1 issue(s)
  • Low: 3 issue(s)

Generated by Auto Claude PR Review

No findings selected for this review.


This review was generated by Auto Claude.

@adryserage
Copy link
Contributor

⚠️ Duplicate PR

This PR appears to be a duplicate of #439, which also fixes Python path handling for paths with spaces.

Recommendation: Close this PR in favor of #439 (created earlier).

Both PRs have the same branch name fix/python-path-spaces and address the same issue.

@MikeeBuilds MikeeBuilds added bug Something isn't working area/backend This is backend only size/XS Extra small (< 10 lines) labels Jan 3, 2026
abe238 and others added 12 commits January 3, 2026 01:04
…unction

- Add ShellType union type for supported shells: powershell, cmd, bash, zsh, fish, sh
- Add detectShellType(shellPath) function to detect shell from executable path
- Supports Windows PowerShell 5.1, PowerShell Core 7+, cmd.exe, Git Bash, WSL bash, zsh, fish
- Defaults to 'bash' for unknown shells (POSIX-compatible fallback)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
… detectShellType

Add comprehensive unit tests for the detectShellType() function:
- PowerShell detection (Windows PowerShell 5.1, pwsh, case insensitivity)
- cmd.exe detection (with and without extension)
- Bash detection (standard paths, Git Bash, WSL)
- Zsh detection
- Fish shell detection
- Bourne shell (sh) detection
- Default fallback to bash for unknown shells

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…h all shell types

Adds comprehensive unit tests for buildCdCommandForShell() covering:
- Undefined/empty path handling for all shell types
- bash/zsh/fish/sh: POSIX single-quote escaping with '\'' for quotes
- PowerShell: Set-Location with single quotes and '' escape for quotes
- cmd.exe: cd /d with double quotes and ^ escape for special chars
- Edge cases: root paths, drive roots, multiple quotes, special chars

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Added comprehensive unit tests for the escapeShellArgPowerShell function:
- Basic escaping: simple strings, empty string, spaces, paths
- Single quote escaping: single, multiple, start/end positions, consecutive
- Special character handling: variables, command substitution, backticks
- Security edge cases: command injection attempts, variable expansion
- Path edge cases: UNC paths, parentheses, brackets, curly braces

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ell type

- Add optional shellType parameter to invokeClaude() function signature
- Import buildCdCommandForShell and ShellType from shell-escape utilities
- Use shell-appropriate cd command syntax when shellType is provided
- Add JSDoc documentation for the new parameter
- Add debug logging for shell type being used

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
… shell awareness

Added shell-aware command generation for profile-based Claude invocation with helpers for buildClearCommand, buildConfigDirCommand, and buildTokenCommand supporting PowerShell, cmd.exe, and POSIX shells.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…handlers

Updated CLAUDE_PROFILE_INITIALIZE handler to be shell-aware:
- Import detectShellType, escapeShellArgPowerShell, and ShellType from shell-escape.ts
- Detect shell type using same logic as pty-manager (COMSPEC/SHELL env vars)
- Generate shell-appropriate login commands for PowerShell, cmd.exe, fish, and POSIX shells
- Use proper escaping for each shell type to prevent command injection

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add shellType property to TerminalProcess interface to track the detected
shell type for each terminal. This enables shell-aware command generation
when invoking Claude or running profile login commands.

- Import ShellType from shell-escape.ts
- Add optional shellType property with JSDoc comment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ash/zsh

- Added 9 backward compatibility tests for buildCdCommand():
  - Verify function exists and is exported
  - Test undefined/empty path handling
  - Test basic path escaping with single quotes
  - Test POSIX single quote escaping (')
  - Test paths with spaces
  - Test paths with special characters ($HOME)
  - Verify identical output to buildCdCommandForShell(path, 'bash')

Manual verification completed:
- buildCdCommand() still exists in shell-escape.ts (lines 109-114)
- Fallback to buildCdCommand() when shellType not provided
  (claude-integration-handler.ts lines 352-354)
- Output equivalence confirmed: both use escapeShellArg() internally

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
SECURITY FIXES:
- Token temp file: Use single quotes with POSIX escaping instead of
  unescaped double quotes to prevent command injection if token
  contains shell metacharacters like $() or backticks
- Add newline/CR stripping to all escape functions to prevent
  multi-line command injection attacks
- escapeShellArg (POSIX): Now strips \r\n before escaping
- escapeShellArgPowerShell: Now strips \r\n before escaping
- escapeShellArgWindows: Now strips \r\n before escaping

TEST COVERAGE:
- Add 65+ new tests for escapeShellArg, escapeShellArgWindows,
  and isPathSafe functions that were previously untested
- Add newline injection prevention tests for all escape functions
- Add command injection security tests for POSIX escaping
- Total tests: 149 (all passing)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@abe238
Copy link
Contributor Author

abe238 commented Jan 3, 2026

Security Fixes Added (Adversarial Analysis)

After running adversarial prompting analysis on the code, I identified and fixed the following security issues:

🔴 CRITICAL: Token temp file vulnerability (FIXED)

File: claude-integration-handler.ts:380

Before (vulnerable):

fs.writeFileSync(tempFile, `export CLAUDE_CODE_OAUTH_TOKEN="${token}"\n`, ...)

After (fixed):

const escapedTokenForExport = token.replace(/'/g, "'\\''");
fs.writeFileSync(tempFile, `export CLAUDE_CODE_OAUTH_TOKEN='${escapedTokenForExport}'\n`, ...)

If a token contained shell metacharacters like $(whoami), it would execute when sourced.

🟠 HIGH: Newline injection prevention (FIXED)

All escape functions now strip \r\n to prevent multi-line command injection:

  • escapeShellArg() - POSIX shells
  • escapeShellArgPowerShell() - PowerShell
  • escapeShellArgWindows() - cmd.exe

📊 Test Coverage Added

Added 65+ new tests covering:

  • escapeShellArg() - previously untested
  • escapeShellArgWindows() - previously untested
  • isPathSafe() - previously untested
  • Newline injection for all escape functions
  • Command injection patterns ($(), backticks, ;, |, &&)

Total tests: 149 (all passing)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01f6300 and 85e230f.

📒 Files selected for processing (5)
  • apps/frontend/src/main/ipc-handlers/terminal-handlers.ts
  • apps/frontend/src/main/terminal/claude-integration-handler.ts
  • apps/frontend/src/main/terminal/types.ts
  • apps/frontend/src/shared/utils/shell-escape.test.ts
  • apps/frontend/src/shared/utils/shell-escape.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/terminal/types.ts
  • apps/frontend/src/main/terminal/claude-integration-handler.ts
  • apps/frontend/src/main/ipc-handlers/terminal-handlers.ts
  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/shared/utils/shell-escape.test.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/terminal/types.ts
  • apps/frontend/src/main/terminal/claude-integration-handler.ts
  • apps/frontend/src/main/ipc-handlers/terminal-handlers.ts
  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/shared/utils/shell-escape.test.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/terminal/types.ts
  • apps/frontend/src/main/terminal/claude-integration-handler.ts
  • apps/frontend/src/main/ipc-handlers/terminal-handlers.ts
  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/shared/utils/shell-escape.test.ts
🧬 Code graph analysis (3)
apps/frontend/src/main/terminal/types.ts (1)
apps/frontend/src/shared/utils/shell-escape.ts (1)
  • ShellType (12-12)
apps/frontend/src/main/terminal/claude-integration-handler.ts (1)
apps/frontend/src/shared/utils/shell-escape.ts (6)
  • ShellType (12-12)
  • escapeShellArgPowerShell (209-216)
  • escapeShellArgWindows (172-190)
  • escapeShellArg (86-93)
  • buildCdCommandForShell (137-160)
  • buildCdCommand (111-116)
apps/frontend/src/main/ipc-handlers/terminal-handlers.ts (1)
apps/frontend/src/shared/utils/shell-escape.ts (5)
  • ShellType (12-12)
  • detectShellType (33-68)
  • escapeShellArgPowerShell (209-216)
  • escapeShellArgWindows (172-190)
  • escapeShellArg (86-93)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (13)
apps/frontend/src/shared/utils/shell-escape.ts (5)

8-68: LGTM! Comprehensive shell detection with sensible defaults.

The detectShellType function correctly identifies common shells across platforms (Windows PowerShell, pwsh, cmd.exe, Git Bash, WSL, zsh, fish, sh) and defaults to bash for unknown shells, which is a safe POSIX-compatible fallback.


86-93: Good security hardening: newline sanitization prevents command injection.

Stripping \r and \n before escaping is a solid defense-in-depth measure against newline-based command injection attacks.


172-190: LGTM! Correct cmd.exe escaping with proper metacharacter handling.

The escaping order (caret first, then other metacharacters) and doubling of % for variable expansion prevention are correct for cmd.exe.


192-216: LGTM! Correct PowerShell single-quote escaping.

Doubling single quotes (''') is the correct escape mechanism for PowerShell literal strings, and newline sanitization adds security.


152-158: The current implementation is correct for fish shell. The POSIX escaping pattern '\'' used in escapeShellArg() works across all POSIX shells including fish because it deliberately exits the quoted context to perform the escape. While fish does support an alternative escape syntax (\' inside single quotes), the current pattern remains valid: the first ' closes the current quoted string, \' escapes the quote outside any quoting context (which fish supports), and the final ' reopens quoting. This approach is universally compatible with bash, zsh, fish, and sh.

apps/frontend/src/main/terminal/types.ts (1)

18-19: LGTM! Clean interface extension with proper documentation.

The optional shellType property is well-documented and maintains backward compatibility with existing code.

apps/frontend/src/main/ipc-handlers/terminal-handlers.ts (1)

336-379: LGTM! Well-implemented shell-aware command construction.

The shell detection and command generation correctly handle:

  • PowerShell: $env:VAR = value; command
  • cmd.exe: set "VAR=value" && command
  • fish: set -x VAR value; and command (correct fish syntax)
  • POSIX shells: export VAR=value && command

Security is maintained through shell-specific escaping functions.

apps/frontend/src/shared/utils/shell-escape.test.ts (2)

294-309: Verify fish shell escaping test expectations.

These tests assume fish uses the same '\'' escaping as POSIX shells. If fish handles single quotes differently (as noted in the shell-escape.ts review), these test expectations may be incorrect and should be updated to match fish's actual behavior.


1-833: Excellent test coverage for shell-escape utilities.

The test suite comprehensively covers:

  • Shell type detection across all supported shells
  • Backward compatibility with buildCdCommand
  • Shell-specific command generation for bash, zsh, fish, sh, PowerShell, and cmd
  • Security edge cases including command injection, newline injection, and special character handling
  • Path edge cases (UNC paths, parentheses, brackets, drive roots)

The equivalence tests between buildCdCommand and buildCdCommandForShell('bash') ensure backward compatibility.

apps/frontend/src/main/terminal/claude-integration-handler.ts (4)

205-224: LGTM! Shell-appropriate clear commands.

Correctly uses Clear-Host for PowerShell, cls for cmd, and clear for POSIX shells with appropriate command separators.


250-260: Consider: fish shell uses bash -c subprocess.

For fish shell, the code falls through to the POSIX case which uses bash -c 'exec claude'. This works but spawns a bash subprocess instead of running natively in fish. This is acceptable since fish can't easily source bash-style export files, but worth noting for debugging if users report issues with fish.


314-321: LGTM! Well-documented optional parameter with backward compatibility.

The shellType parameter is optional and the function correctly falls back to POSIX-style commands when not specified, maintaining backward compatibility.


370-395: Good security design: temp file for POSIX, direct env for Windows shells.

The branching logic correctly uses:

  • Temp file method for POSIX shells (avoids token in command line/history)
  • Direct environment variable setting for PowerShell/cmd (these shells don't have source equivalent, and the escaping functions handle security)

This is a sensible security/compatibility tradeoff.

Comment on lines +380 to +383
// SECURITY: Use single quotes to prevent any variable expansion or command substitution
// Escape any single quotes in the token using POSIX escaping: ' → '\''
const escapedTokenForExport = token.replace(/'/g, "'\\''");
fs.writeFileSync(tempFile, `export CLAUDE_CODE_OAUTH_TOKEN='${escapedTokenForExport}'\n`, { mode: 0o600 });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using escapeShellArg for consistency.

The manual POSIX escaping token.replace(/'/g, "'\\''") duplicates the logic in escapeShellArg. Consider reusing the utility, though note that escapeShellArg also strips newlines and wraps in quotes, so the current approach is correct for the export statement context.

🔎 Optional refactor for consistency
-        // SECURITY: Use single quotes to prevent any variable expansion or command substitution
-        // Escape any single quotes in the token using POSIX escaping: ' → '\''
-        const escapedTokenForExport = token.replace(/'/g, "'\\''");
-        fs.writeFileSync(tempFile, `export CLAUDE_CODE_OAUTH_TOKEN='${escapedTokenForExport}'\n`, { mode: 0o600 });
+        // SECURITY: Use escapeShellArg which handles single quotes and strips newlines
+        const escapedToken = escapeShellArg(token);
+        fs.writeFileSync(tempFile, `export CLAUDE_CODE_OAUTH_TOKEN=${escapedToken}\n`, { mode: 0o600 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// SECURITY: Use single quotes to prevent any variable expansion or command substitution
// Escape any single quotes in the token using POSIX escaping: ' → '\''
const escapedTokenForExport = token.replace(/'/g, "'\\''");
fs.writeFileSync(tempFile, `export CLAUDE_CODE_OAUTH_TOKEN='${escapedTokenForExport}'\n`, { mode: 0o600 });
// SECURITY: Use escapeShellArg which handles single quotes and strips newlines
const escapedToken = escapeShellArg(token);
fs.writeFileSync(tempFile, `export CLAUDE_CODE_OAUTH_TOKEN=${escapedToken}\n`, { mode: 0o600 });
🤖 Prompt for AI Agents
In apps/frontend/src/main/terminal/claude-integration-handler.ts around lines
380-383, replace the manual POSIX escaping token.replace(/'/g, "'\\''") with the
shared escapeShellArg utility for consistency: call escapeShellArg(token) and
use its return value directly in the export assignment (it already wraps in
quotes and escapes single quotes), updating the fs.writeFileSync call
accordingly; ensure this change is acceptable given escapeShellArg strips
newlines—if preserving newlines is required, keep the current manual replace but
add a comment referencing escapeShellArg and why manual escaping is necessary.

- Use parsePythonCommand + execFileSync in getPythonVersion (fixes MEDIUM)
- Add /root/.pyenv pattern for Linux root user (from adversarial analysis)
- Remove unused execSync import
- Tighten regex patterns: pyenv/conda require explicit home directories
- Add 23 unit tests for parsePythonCommand and validatePythonPath

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/frontend/src/main/python-detector.ts (1)

319-321: Windows venv patterns are overly permissive compared to Unix equivalents.

These patterns use ^.*\\ prefix which allows any path, including potentially malicious locations (e.g., C:\attacker\controlled\.venv\Scripts\python.exe). The Unix venv patterns (lines 312-314) are more restrictive, requiring alphanumeric directory names.

🔎 Proposed fix to constrain Windows venv patterns
   // Windows virtual environments
-  /^.*\\\.?venv\\Scripts\\python\.exe$/i,
-  /^.*\\\.?virtualenv\\Scripts\\python\.exe$/i,
-  /^.*\\env\\Scripts\\python\.exe$/i,
+  // Only allow alphanumeric, dash, underscore, dot, and space in directory names
+  /^(?:[A-Za-z]:\\)?(?:[a-zA-Z0-9._\- ]+\\)+\.?venv\\Scripts\\python\.exe$/i,
+  /^(?:[A-Za-z]:\\)?(?:[a-zA-Z0-9._\- ]+\\)+\.?virtualenv\\Scripts\\python\.exe$/i,
+  /^(?:[A-Za-z]:\\)?(?:[a-zA-Z0-9._\- ]+\\)+env\\Scripts\\python\.exe$/i,
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85e230f and a79a02d.

📒 Files selected for processing (2)
  • apps/frontend/src/main/__tests__/python-detector.test.ts
  • apps/frontend/src/main/python-detector.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/__tests__/python-detector.test.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/__tests__/python-detector.test.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/__tests__/python-detector.test.ts
  • apps/frontend/src/main/python-detector.ts
🧬 Code graph analysis (1)
apps/frontend/src/main/__tests__/python-detector.test.ts (1)
apps/frontend/src/main/python-detector.ts (2)
  • parsePythonCommand (222-278)
  • validatePythonPath (414-503)
🪛 GitHub Actions: CI
apps/frontend/src/main/__tests__/python-detector.test.ts

[error] 3-3: Cannot find name 'describe'. Do you need to install type definitions for a test runner? Try 'npm i --save-dev @types/jest' or 'npm i --save-dev @types/mocha'.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (7)
apps/frontend/src/main/__tests__/python-detector.test.ts (1)

97-150: Good security test coverage for validatePythonPath.

The tests comprehensively cover dangerous shell metacharacters ($(), backticks, ;, |, newlines), path traversal, and null/empty inputs. This aligns well with the security hardening in the PR.

Consider adding tests for mixed-quote scenarios (e.g., "/path/to/'python") and Windows UNC paths if those are expected inputs.

apps/frontend/src/main/python-detector.ts (6)

129-145: Good security improvement using execFileSync with shell: false.

Using parsePythonCommand to split the command and args, then executing with execFileSync and shell: false correctly addresses the spawn ENOENT issue for paths with spaces while preventing shell injection.


240-258: Core fix correctly implemented: path separators checked before existence.

The reordering to check hasPathSeparators before existsSync (lines 240-258) correctly addresses the root cause where non-existent venv paths were incorrectly split on spaces. The detailed comments explain the rationale well.


363-367: Dual path testing handles cross-platform patterns correctly.

Testing both the original path and the normalized path ensures Windows patterns (with \) and Unix patterns (with /) both match appropriately.


385-400: Consistent secure execution pattern in verifyIsPython.

Uses the same parsePythonCommand + execFileSync with shell: false pattern as getPythonVersion, maintaining consistent security posture.


293-293: Comprehensive dangerous character detection including newlines.

The regex correctly covers shell metacharacters for command injection (; | &), subshells ($ ( ) \``), redirects (< >), globs (* ? [ ]), and newline injection (\n \r`). This aligns with the security fixes mentioned in the PR comments.


452-461: Path traversal check is effective; reasoning in original comment was incorrect.

The concern about path.normalize() was based on a misunderstanding. While path.normalize() does resolve .. segments in absolute paths, it does NOT fully resolve relative paths—relative traversal sequences like ../../etc/passwd remain in the normalized string and are caught by the includes('..') check.

For absolute paths that attempt traversal, the strict allowlist at line 464 provides the primary defense. All 30+ patterns are absolute paths for known safe locations (system Python, Homebrew, pyenv, virtual environments, conda). A path that escapes these directories would fail the allowlist check regardless.

The security design is sound: relative traversal is caught by the string check, and absolute paths are restricted to allowlisted locations.

Comment on lines +1 to +3
import { parsePythonCommand, validatePythonPath } from '../python-detector';

describe('parsePythonCommand', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Add Jest type definitions to fix pipeline failure.

The CI pipeline reports Cannot find name 'describe'. The test file needs Jest type definitions to compile.

🔎 Proposed fix

Add the import at the top of the file or install @types/jest:

+/// <reference types="jest" />
 import { parsePythonCommand, validatePythonPath } from '../python-detector';

 describe('parsePythonCommand', () => {

Alternatively, ensure @types/jest is installed and included in tsconfig.json:

npm i --save-dev @types/jest
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { parsePythonCommand, validatePythonPath } from '../python-detector';
describe('parsePythonCommand', () => {
/// <reference types="jest" />
import { parsePythonCommand, validatePythonPath } from '../python-detector';
describe('parsePythonCommand', () => {
🧰 Tools
🪛 GitHub Actions: CI

[error] 3-3: Cannot find name 'describe'. Do you need to install type definitions for a test runner? Try 'npm i --save-dev @types/jest' or 'npm i --save-dev @types/mocha'.

🤖 Prompt for AI Agents
In apps/frontend/src/main/__tests__/python-detector.test.ts around lines 1 to 3,
the test file fails to compile because Jest globals like "describe" are not
recognized; fix by either adding Jest type definitions to the file (e.g., add a
single line at the top referencing Jest types) or install and enable @types/jest
project-wide (npm i --save-dev @types/jest) and ensure tsconfig.json includes
"jest" in the "types" array or the test tsconfig includes the Jest types so the
compiler recognizes Jest globals.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
apps/frontend/src/shared/utils/shell-escape.ts (1)

112-126: Potential inconsistency: buildCdCommand uses platform detection while buildCdCommandForShell uses shell type.

buildCdCommand assumes win32 platform means cmd.exe, but users on Windows may run PowerShell or Git Bash. Consider deprecating this function in favor of buildCdCommandForShell which uses explicit shell type detection, or update it to detect the shell type.

apps/frontend/src/main/python-detector.ts (3)

309-311: Windows venv patterns use overly permissive .* prefix.

Lines 309-311 use ^.*\\ which matches any prefix, potentially allowing malicious paths. Consider constraining to known safe locations similar to the Unix patterns.

🔎 Suggested stricter Windows venv patterns
   // Windows virtual environments
-  /^.*\\\.?venv\\Scripts\\python\.exe$/i,
-  /^.*\\\.?virtualenv\\Scripts\\python\.exe$/i,
-  /^.*\\env\\Scripts\\python\.exe$/i,
+  // Windows virtual environments - constrained to user directories
+  /^[A-Za-z]:\\Users\\[^\\]+\\[^\\]+\\\.?venv\\Scripts\\python\.exe$/i,
+  /^[A-Za-z]:\\Users\\[^\\]+\\[^\\]+\\\.?virtualenv\\Scripts\\python\.exe$/i,
+  /^[A-Za-z]:\\Users\\[^\\]+\\[^\\]+\\env\\Scripts\\python\.exe$/i,

355-359: Path normalization may cause regex mismatch on Windows.

matchesAllowedPattern normalizes backslashes to forward slashes for matching, but most Windows patterns in ALLOWED_PATH_PATTERNS expect backslashes. The function tests both the original and normalized path, which should work, but this dual-testing approach is fragile.

Consider normalizing all patterns to use forward slashes, or explicitly document which patterns expect which separator style:

🔎 Suggested clarification
 function matchesAllowedPattern(pythonPath: string): boolean {
-  // Normalize path separators for consistent matching
+  // Test both original path (for Windows backslash patterns) and 
+  // normalized path (for Unix forward-slash patterns)
   const normalizedPath = pythonPath.replace(/\\/g, '/');
   return ALLOWED_PATH_PATTERNS.some(pattern => pattern.test(pythonPath) || pattern.test(normalizedPath));
 }

497-509: Consider logging successful validations for debugging.

Currently only invalid paths are logged. Consider adding a debug log for successful validations to aid troubleshooting path-with-spaces issues in production.

🔎 Suggested logging improvement
 export function getValidatedPythonPath(providedPath: string | undefined, serviceName: string): string {
   if (!providedPath) {
     return findPythonCommand() || 'python';
   }

   const validation = validatePythonPath(providedPath);
   if (validation.valid) {
+    console.log(`[${serviceName}] Validated Python path: ${validation.sanitizedPath}`);
     return validation.sanitizedPath || providedPath;
   }

   console.error(`[${serviceName}] Invalid Python path rejected: ${validation.reason}`);
   return findPythonCommand() || 'python';
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a79a02d and 484aef0.

📒 Files selected for processing (2)
  • apps/frontend/src/main/python-detector.ts
  • apps/frontend/src/shared/utils/shell-escape.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/main/python-detector.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/shared/utils/shell-escape.ts
  • apps/frontend/src/main/python-detector.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (11)
apps/frontend/src/shared/utils/shell-escape.ts (5)

8-68: LGTM! Shell type detection is well-structured.

The detectShellType function correctly identifies various shell types with reasonable defaults. The order of checks is appropriate (more specific patterns before generic ones), and defaulting to bash for unknown shells is a sensible POSIX-compatible fallback.


86-93: Good security fix: newline/CR sanitization prevents command injection.

Stripping \r\n before escaping single quotes closes a command injection vector where an attacker could break out of single-quoted strings using newlines. This is a solid defense-in-depth approach.


147-170: LGTM! Shell-specific cd command generation is well-implemented.

The function correctly uses:

  • Set-Location with semicolon separator for PowerShell
  • cd /d with & separator for cmd.exe (supporting drive changes)
  • Standard cd with && for POSIX shells

Each shell type uses its appropriate escaping function.


182-200: Good security hardening with newline removal.

The addition of \r and \n removal (lines 196-197) closes a command injection vector in cmd.exe. The order of escape operations is correct—carets are escaped first since ^ is the escape character.


219-226: LGTM! PowerShell escaping is correct.

PowerShell single-quoted strings only require doubling single quotes ('''), and newline sanitization is properly applied before escaping.

apps/frontend/src/main/python-detector.ts (6)

1-1: Good security improvement: switching to execFileSync.

Using execFileSync with shell: false prevents shell injection attacks when executing Python commands, especially important for paths containing spaces or special characters.


119-135: LGTM! Safe Python version extraction.

Using execFileSync with shell: false and parsePythonCommand correctly handles paths with spaces without shell interpretation issues.


230-268: LGTM! Correct reordering fixes the path-with-spaces issue.

The key fix: checking for path separators (/ or \) before existsSync ensures that paths like /Users/user/Library/Application Support/App/python-venv/bin/python are treated as single paths rather than split on spaces, even when the venv doesn't exist yet during initial setup.

The logic flow is now:

  1. Has path separators and doesn't start with - → treat as path (no split)
  2. File exists without separators → treat as executable in current directory
  3. Otherwise → split on spaces for commands like py -3

This correctly handles the root cause described in the PR.


377-392: LGTM! Safe Python verification.

Using execFileSync with shell: false and verifying the output matches Python X.Y is a solid defense-in-depth measure to ensure the executable is actually Python.


406-495: Comprehensive validation with good layered security.

The validation flow is well-structured:

  1. Shell metacharacter rejection
  2. Safe command allowlist check
  3. Path traversal detection
  4. Allowlist pattern matching
  5. Existence and executability checks
  6. Runtime Python verification

This defense-in-depth approach significantly reduces command injection risk.


296-307: The regex patterns work correctly; the concern about unescaped spaces is based on a misunderstanding of regex syntax.

Spaces inside character classes [ ] do not require escaping and are literal characters in regex. The test results confirm all patterns match their intended paths:

  • Virtual environment patterns correctly match /home/user/my-project/.venv/bin/python paths
  • macOS Application Support pattern correctly matches /Users/*/Library/Application Support/*/venv/bin/python paths
  • Character classes with spaces function as intended

The patterns are internal path validation logic, not user-facing text, so no changes are needed.

Likely an incorrect or invalid review comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AC: Approved area/backend This is backend only bug Something isn't working size/XS Extra small (< 10 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants